package com.gopay.cashier.web.controller;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.gopay.common.constants.trans.GatewaySource;
import com.gopay.common.constants.trans.OrderFeePayer;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.domain.cashier.PayDoneResult;
import com.gopay.common.domain.cashier.PayWay;
import com.gopay.common.domain.cps.gp.CpsGpContractInfo;
import com.gopay.common.domain.cps.vo.CPSResponse;
import com.gopay.remote.cps.cashier.CashierCheckAcctBalanceRemoteService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.service.gsrt.GsrtService;
import com.gopay.cashier.web.command.GopayChannelCommand;
import com.gopay.cashier.web.utils.BisBankBusinessProdConvertUtil;
import com.gopay.cashier.web.utils.CashierConfig;
import com.gopay.common.constants.YnFlag;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.PayChannel;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.acps.AcctStatus;
import com.gopay.common.domain.acps.FrezCode;
import com.gopay.common.domain.acps.model.AcctMastBean;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.user.UserPayPwdResult;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.PwdControlUtil;
import com.gopay.remote.order.MainOrderField;

/**
 *	@author Administrator
 *	支付确认
 *	@ToBisController
 */
@Controller
public class PayConfirmController extends BaseController{

    @Resource(name = "p2pTransferCheck")
    private CashierCheckAcctBalanceRemoteService p2pTransferCheck;
    
    @Resource(name="gsrtService")
    private GsrtService gsrtService;

    protected final static Log logger = LogFactory.getLog("PAY-CONFIRM");
    /**
     * 入金交易确认
     * @param command
     * @return
     * @throws GopayException
     */
	@RequestMapping(value = "/sec/pay/confirm.shtml")
	public ModelAndView execute(GopayChannelCommand command) throws GopayException{
        printRequest();
        //充值订单
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);
        
        CpsGenMainOrder order = getMainOrder(orderId, true);
        // 验证
        if(!validate(command, order)){
        	return back(order);
        }
        
        String orderDate = DateUtils.format(order.getGopayTxnTm());
        BigDecimal amount = order.getTotalOrderAmt();
        String bank = order.getOutStlmId();

        updateOrder(command, order);
        return next(order.getGopayOrderId(), orderDate, bank, amount,order.getPayChannel());
	}

    /**
     * p2p 网银支付 确认
     * @param command
     * @return
     * @throws GopayException
     */
    @RequestMapping(value = "/pay/bankConfirm.shtml")
    public ModelAndView bankConfirm(GopayChannelCommand command) throws GopayException{
        //风控额度校验
        checkTranAmtLimit();
        return execute(command);
    }

    /**
     * p2p国付宝账户支付 确认
     * @param command
     * @return
     * @throws GopayException
     */
    @RequestMapping(value = "/sec/pay/gopayConfirm.shtml")
    public ModelAndView gopayConfirm(GopayChannelCommand command) throws GopayException{
        printRequest();
        CpsGenMainOrder order = getMainOrder(getOrderId(), true);
        //风控额度校验
        checkTranAmtLimit();
        // 校验
        if(!validate(command, order)){
            return back(order);
        }
        // 调用cps执行支付完成处理
        completeOrder(order);

        return new ModelAndView(new RedirectView("gopayResult.shtml?orderId="+order.getGopayOrderId()));
    }

    private ModelAndView back(CpsGenMainOrder order)  throws WebException {
    	HttpServletRequest request = getRequest();
//    	Map<String, String> pm = new HashMap<String, String>();
//    	pm.put("orderId",order.getGopayOrderId());
    	if(request.getAttribute(FIELD_ERR_MSG)!=null && StringUtils.isNotBlank((String)request.getAttribute(FIELD_ERR_MSG))){
    		request.getSession().setAttribute(FIELD_ERR_MSG, request.getAttribute(FIELD_ERR_MSG));
    	}
    	return new ModelAndView(new RedirectView(request.getContextPath()+"/sec/pay/info.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+order.getGopayOrderId()));
    }
    
	private boolean validate(GopayChannelCommand command, final CpsGenMainOrder order) throws GopayException {
        CpsGenMainOrder realOrder = order;
        if (null == realOrder) {
            logger.error("找不到订单！order not exits!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (TxnStaCode.TXN_STA_CD_20000.value == (realOrder.getTxnStaCd())) {
            logger.error("订单已经支付成功，中断处理！order is finished!" + command + ", " + realOrder);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }

        if (YnFlag.y.code.equals(needPaypwd(realOrder))) {// 判断此订单需要验证支付密码 ；
            if (!validateSessionKey(getRequest(), command.getFormhash())) {
                logger.error("流程异常！ " + realOrder);
                throw new WebException(ProcCodeConstants.PROC_CODE_100F1002);
            }
            String payPwd = null;
            try {
            	payPwd = PwdControlUtil.decryptPwd(getRequest(), command.getPayPassword());
			} catch (Exception e) {
				logger.error(e.getMessage());
			}
            if(StringUtils.isBlank(payPwd))
            	throw new WebException(ProcCodeConstants.PROC_CODE_100E3007);
            
            LoginUser lu = getLoginUser();
            UserInfo userInfo = lu.getUser();
            
            UserPayPwdResult res = userPayPwdManager.verifyPayPwd(userInfo.getUserId(), payPwd);
            if (!res.isVerifySuccess()) {
            	getRequest().setAttribute(FIELD_ERR_MSG, res.getErrorMsg());
                return false;
            }
        }

        realOrder = getInchargeOrgOrder(order, true);

        checkRecvCustStatus(0, realOrder.getMainRecvCustId());

        if (StringUtils.isNotBlank(realOrder.getPayAcct())) {
            AcctMastBean acct = acctTransService.getAccount(realOrder.getPayAcct());
            if (null == acct) {
                logger.error("账户不存在,acctId=" + realOrder.getPayAcct());
                throw new WebException(ProcCodeConstants.PROC_CODE_100E6012);
            }
            if (AcctStatus.F.equals(acct.getAccStatus())) {
                if (FrezCode.DEB.equals(acct.getFrezCode()) || FrezCode.CRE.equals(acct.getFrezCode())
                        || FrezCode.FUL.equals(acct.getFrezCode())) {
                    throw new GopayException(ProcCodeConstants.PROC_CODE_100E3026, "账户[" + realOrder.getPayAcct()
                            + "]处于冻结状态[" + acct.getFrezCode() + "]，无法出款");
                }
            }
        }
        AcctMastBean acct = acctTransService.getAccount(realOrder.getMainRecvAcct());
        if (null == acct) {
            logger.error("账户不存在,acctId=" + realOrder.getPayAcct());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E6012);
        }
        if (AcctStatus.F.equals(acct.getAccStatus())) {
            if (FrezCode.CRE.equals(acct.getFrezCode()) || FrezCode.FUL.equals(acct.getFrezCode())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E3025, "账户[" + realOrder.getPayAcct()
                        + "]处于冻结状态[" + acct.getFrezCode() + "]，无法出款");
            }
        }
        //校验p2p交易
        checkP2PFeeAmt(order);

        return true;
    }
	/**
     * @param gopayOrderId
     *            - 如果是登录后网银支付，为充值订单的订单号
	 * @throws WebException 
     */
    private  ModelAndView next(String gopayOrderId, String orderDate, String bank, BigDecimal amount,String payChannel) throws WebException {
    	getRequest().getSession().removeAttribute(CAS_GOPAY_USER);
    	getRequest().getSession().removeAttribute(GOPAY_ORDER_ID);
    	
        ModelAndView mav = new ModelAndView("pay/bankPayForBis");
        mav.addObject("orderId", gopayOrderId);
        mav.addObject("amount", amount.toString());
        mav.addObject("orderDate", orderDate);
        mav.addObject("userType", "");
        mav.addObject("bank", bank);
        mav.addObject("bisUrl", CashierConfig.get(CashierConfig.BIS_URL));
        mav.addObject("bankBusProd", BisBankBusinessProdConvertUtil.getBisBankBusinessProd(PayChannel.get(payChannel)).value);

        setB2BBankConfig(mav,PayChannel.get(payChannel),bank);
        return mav;
    }

    
    private void updateOrder(GopayChannelCommand command, CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        try {
            logger.error("调用cps更新直连银行订单状态.BEGIN.call cps to update DirectBankPay order" + command + ", " + order + ", "
                    + values);
            mainOrderUpdateService.updateMany(order.getGopayOrderId(), values);
            //如果是G商融通的充值，则去更新G商融通充值业务表
            if(StringUtils.equals(order.getGatewaySource(), GatewaySource.GATEWAY_SOURCE_09.value)){
            	gsrtService.updateGsrtRecharge(order.getGopayOrderId());
            }
            logger.error("调用cps更新直连银行订单状态.END.call cps to update DirectBankPay order" + command + ", " + order);
        } catch (GopayException e) {
            logger.error("调用cps更新直连银行订单状态出错！call cps to update DirectBankPay order error!" + command + ", " + order, e);
            throw new WebException(e.getErrCode());
        }
    }
    private void completeOrder(CpsGenMainOrder order) throws GopayException {
        PayDoneResult r = new PayDoneResult();
        r.setSuccess(true);
        r.setPayWay(PayWay.AcctPay);
        r.setOrderId(order.getGopayOrderId());
        logger.error("账户支付返回-调用cps执行支付完成处理.BEGIN. call cashierPayCallbackService.finish." + r);
        String result = cashierPayCallbackService.finish(r);
        logger.error("账户支付返回-调用cps执行支付完成处理.END. call cashierPayCallbackService.finish." + r);
        if (!ProcCodeConstants.PROC_CODE_000S1000.equals(result)
                && !ProcCodeConstants.PROC_CODE_100S1000.equals(result)) {
            throw new GopayException(result);
        }
        getRequest().getSession().removeAttribute(CAS_GOPAY_USER);
        getRequest().getSession().removeAttribute(GOPAY_ORDER_ID);
    }

    /**
     * 校验p2p交易 手续费平台承担的余额
     */
    private void checkP2PFeeAmt(CpsGenMainOrder newOrder) throws GopayException{
        CpsGenMainOrder p2pOrder = null;
        if(isP2P(newOrder)){
            //p2p虚拟账户付款
            p2pOrder = newOrder;
        }else  if(StringUtils.isNotBlank(newOrder.getRelevanceGopayOrderId())){
            CpsGenMainOrder order = getMainOrder(newOrder.getRelevanceGopayOrderId(), true);
            if(order!=null && isP2P(order)){
                p2pOrder = order;
            }
        }
        if(p2pOrder != null){
            logger.info("orderId:"+p2pOrder.getGopayOrderId()+",intTxnCd:"+p2pOrder.getGopayIntTxnCd()+",freePayer:"+p2pOrder.getOrderFeePayer());
            if(!StringUtils.equals(p2pOrder.getGopayIntTxnCd(), IntTxnCd._01302.value)){
                if(StringUtils.equals(p2pOrder.getOrderFeePayer(), OrderFeePayer.MER_PAYER.value)){
                    CpsGpContractInfo info = cpsGpContractInfoDAO.getByContractNo(p2pOrder.getRemark1());
                    if(info!=null){
                        AcctMastBean acct = acctTransService.getAccount(info.getTrustAcct());//平台账号
                        if(new BigDecimal(acct.getAvaAmt()).compareTo(p2pOrder.getTotalOrderFeeAmt())==-1){
                            throw new WebException(ProcCodeConstants.PROC_CODE_100E7024);
                        }
                    }
                }
            }else{
                //p2p 转账交易校验
                CPSResponse response = p2pTransferCheck.checkGp01302AcctBanlanceEnough(p2pOrder.getGopayOrderId());
                if(response == null){
                    logger.error("checkGp01302AcctBanlanceEnough response is null for orderId:"+p2pOrder.getGopayOrderId());
                    return;
                }
                logger.info("p2pTransferCheck orderId :"+p2pOrder.getGopayOrderId()+","+response.getRespCode()+":"+response.getRespMessage());
                if(!StringUtils.equals(ProcCodeConstants.PROC_CODE_000S1000,response.getRespCode())){
                    throw new GopayException(response.getRespCode(),response.getRespMessage());
                }
            }
        }
    }
}
